package demoMod.invincibleOne.ui;

import basemod.BaseMod;
import basemod.abstracts.CustomSavable;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.Vector2;
import com.google.gson.reflect.TypeToken;
import com.megacrit.cardcrawl.dungeons.AbstractDungeon;
import com.megacrit.cardcrawl.helpers.MathHelper;
import demoMod.invincibleOne.InvincibleOneMod;
import demoMod.invincibleOne.characters.InvincibleOne;

import java.lang.reflect.Type;
import java.util.*;
import java.util.stream.Collectors;

public class BingoPanel implements CustomSavable<List<BingoItem>> {
    private final List<BingoSlot> slots = new ArrayList<>();

    private float alpha = 1.0F;

    public boolean hide = true;

    public static final int LINES = 5;
    public static final int COLUMNS = 5;

    public BingoPanel() {
        BaseMod.addSaveField("BingoPanel", this);
    }

    public void initBingoPanel() {
        if (!(AbstractDungeon.player instanceof InvincibleOne)) {
            return;
        }
        Arrays.stream(BingoItem.values()).forEach(BingoItem::reset);
        slots.clear();
        List<BingoItem> easyBingoItems = Arrays.stream(BingoItem.values()).filter(bingoItem -> bingoItem.getDifficulty() == 0).collect(Collectors.toList());
        List<BingoItem> hardBingoItem = Arrays.stream(BingoItem.values()).filter(bingoItem -> bingoItem.getDifficulty() == 1).collect(Collectors.toList());
        List<BingoItem> bingoRewards = new ArrayList<>();
        bingoRewards.add(BingoItem.REWARD_LEGEND_CARD_A);
        bingoRewards.add(BingoItem.REWARD_LEGEND_CARD_B);
        bingoRewards.add(BingoItem.REWARD_LEGEND_CARD_C);
        bingoRewards.add(BingoItem.REWARD_LEGEND_CARD_D);
        bingoRewards.add(BingoItem.REWARD_CARD_A);
        bingoRewards.add(BingoItem.REWARD_CARD_REMOVAL_A);
        bingoRewards.add(BingoItem.REWARD_CARD_REMOVAL_B);
        bingoRewards.add(BingoItem.REWARD_CARD_B);
        bingoRewards.add(BingoItem.REWARD_BLANK);
        Collections.shuffle(easyBingoItems, new Random(AbstractDungeon.shuffleRng.randomLong()));
        Collections.shuffle(hardBingoItem, new Random(AbstractDungeon.shuffleRng.randomLong()));
        for (int i=0; i<LINES * COLUMNS; i++) {
            BingoItem item;
            if (i == getIndexByCoordinates(1, 1) || i == getIndexByCoordinates(1, 2) || i == getIndexByCoordinates(2, 1) || i == getIndexByCoordinates(2, 2)) {
                item = hardBingoItem.remove(0);
            } else {
                Vector2 axis = getCoordinatesByIndex(i);
                if (axis.x == LINES - 1 || axis.y == COLUMNS - 1) {
                    item = bingoRewards.remove(0);
                } else {
                    item = easyBingoItems.remove(0);
                }
            }
            BingoSlot slot = new BingoSlot(item);
            slots.add(slot);
        }
    }

    public static int getIndexByCoordinates(int lines, int columns) {
        return lines * COLUMNS + columns;
    }

    public static Vector2 getCoordinatesByIndex(int index) {
        Vector2 ret = new Vector2();
        ret.x = index / LINES;
        ret.y = index % COLUMNS;
        return ret;
    }

    public static Vector2 getCoordinatesBySlot(BingoSlot slot) {
        int index = InvincibleOneMod.bingoPanel.getSlots().indexOf(slot);
        Vector2 ret = new Vector2();
        ret.x = index / LINES;
        ret.y = index % COLUMNS;
        return ret;
    }

    public void update() {
        if (!(AbstractDungeon.player instanceof InvincibleOne)) {
            return;
        }
        slots.forEach(BingoSlot::update);
        float targetAlpha = 1.0F;
        if (hide) {
            targetAlpha = 0.0F;
        }
        alpha = MathHelper.fadeLerpSnap(alpha, targetAlpha);
    }

    public void render(SpriteBatch sb) {
        if (!(AbstractDungeon.player instanceof InvincibleOne)) {
            return;
        }
        slots.forEach(slot -> slot.render(sb, alpha));
    }

    public List<BingoSlot> getSlots() {
        return slots;
    }

    @Override
    public List<BingoItem> onSave() {
        return slots.stream().map(BingoSlot::getBingoItem).collect(Collectors.toList());
    }

    @Override
    public void onLoad(List<BingoItem> bingoItems) {
        if (bingoItems != null) {
            slots.clear();
            bingoItems.forEach(item -> slots.add(new BingoSlot(item)));
        }
    }

    @Override
    public Type savedType() {
        return new TypeToken<List<BingoItem>>(){}.getType();
    }
}
